﻿using System;
using System.IO;
using System.Text;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Algorithm;
using YJKGridTopologyCal.GeometriesGraph.Index;

namespace YJKGridTopologyCal.GeometriesGraph
{
	public class Edge : GraphComponent
	{
		public static void UpdateIM(Label label, IntersectionMatrix im)
		{
			im.SetAtLeastIfValid(label.GetLocation(0, Positions.On), label.GetLocation(1, Positions.On), Dimension.Curve);
			if (label.IsArea())
			{
				im.SetAtLeastIfValid(label.GetLocation(0, Positions.Left), label.GetLocation(1, Positions.Left), Dimension.Surface);
				im.SetAtLeastIfValid(label.GetLocation(0, Positions.Right), label.GetLocation(1, Positions.Right), Dimension.Surface);
			}
		}

		public Edge(Coordinate[] pts, Label label)
		{
			this._eiList = new EdgeIntersectionList(this);
			this._pts = pts;
			base.Label = label;
		}

		public Edge(Coordinate[] pts) : this(pts, null)
		{
		}

		public Coordinate[] Points
		{
			get
			{
				return this._pts;
			}
			set
			{
				this._pts = value;
			}
		}

		public int NumPoints
		{
			get
			{
				return this.Points.Length;
			}
		}

		public string Name
		{
			get
			{
				return this._name;
			}
			set
			{
				this._name = value;
			}
		}

		public Coordinate[] Coordinates
		{
			get
			{
				return this.Points;
			}
		}

		public Coordinate GetCoordinate(int i)
		{
			Coordinate result;
			try
			{
				result = this.Points[i];
			}
			catch (Exception ex)
			{
				throw ex;
			}
			return result;
		}

		public override Coordinate Coordinate
		{
			get
			{
				if (this.Points.Length == 0)
				{
					return null;
				}
				return this.Points[0];
			}
			protected set
			{
				throw new NotSupportedException();
			}
		}

		public Envelope Envelope
		{
			get
			{
				if (this._env == null)
				{
					this._env = new Envelope();
					for (int i = 0; i < this.Points.Length; i++)
					{
						this._env.ExpandToInclude(this.Points[i]);
					}
				}
				return this._env;
			}
		}

		public Depth Depth
		{
			get
			{
				return this._depth;
			}
		}

		public int DepthDelta
		{
			get
			{
				return this._depthDelta;
			}
			set
			{
				this._depthDelta = value;
			}
		}

		public int MaximumSegmentIndex
		{
			get
			{
				return this.Points.Length - 1;
			}
		}

		public EdgeIntersectionList EdgeIntersectionList
		{
			get
			{
				return this._eiList;
			}
		}

		public MonotoneChainEdge MonotoneChainEdge
		{
			get
			{
				if (this._mce == null)
				{
					this._mce = new MonotoneChainEdge(this);
				}
				return this._mce;
			}
		}

		public bool IsClosed
		{
			get
			{
				return this.Points[0].Equals(this.Points[this.Points.Length - 1]);
			}
		}

		public bool IsCollapsed
		{
			get
			{
				return base.Label.IsArea() && this.Points.Length == 3 && this.Points[0].Equals(this.Points[2]);
			}
		}

		public Edge CollapsedEdge
		{
			get
			{
				return new Edge(new Coordinate[]
				{
					this.Points[0],
					this.Points[1]
				}, Label.ToLineLabel(base.Label));
			}
		}

		public bool Isolated
		{
			get
			{
				return this._isIsolated;
			}
			set
			{
				this._isIsolated = value;
			}
		}

		public override bool IsIsolated
		{
			get
			{
				return this._isIsolated;
			}
		}

		public void AddIntersections(LineIntersector li, int segmentIndex, int geomIndex)
		{
			for (int i = 0; i < li.IntersectionNum; i++)
			{
				this.AddIntersection(li, segmentIndex, geomIndex, i);
			}
		}

		public void AddIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex)
		{
			Coordinate coordinate = new Coordinate(li.GetIntersection(intIndex));
			int num = segmentIndex;
			double dist = li.GetEdgeDistance(geomIndex, intIndex);
			int num2 = num + 1;
			if (num2 < this.Points.Length)
			{
				Coordinate other = this.Points[num2];
				if (coordinate.Equals2D(other))
				{
					num = num2;
					dist = 0.0;
				}
				this.EdgeIntersectionList.Add(coordinate, num, dist);
			}
		}

		public override void ComputeIM(IntersectionMatrix im)
		{
			Edge.UpdateIM(base.Label, im);
		}

		public override bool Equals(object o)
		{
			return o != null && o is Edge && this.Equals(o as Edge);
		}

		protected bool Equals(Edge e)
		{
			if (this.Points.Length != e.Points.Length)
			{
				return false;
			}
			bool flag = true;
			bool flag2 = true;
			int num = this.Points.Length;
			for (int i = 0; i < this.Points.Length; i++)
			{
				if (!this.Points[i].Equals2D(e.Points[i]))
				{
					flag = false;
				}
				if (!this.Points[i].Equals2D(e.Points[--num]))
				{
					flag2 = false;
				}
				if (!flag && !flag2)
				{
					return false;
				}
			}
			return true;
		}

		public static bool operator ==(Edge obj1, Edge obj2)
		{
			return object.Equals(obj1, obj2);
		}

		public static bool operator !=(Edge obj1, Edge obj2)
		{
			return !(obj1 == obj2);
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}

		public bool IsPointwiseEqual(Edge e)
		{
			if (this.Points.Length != e.Points.Length)
			{
				return false;
			}
			for (int i = 0; i < this.Points.Length; i++)
			{
				if (!this.Points[i].Equals2D(e.Points[i]))
				{
					return false;
				}
			}
			return true;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("edge " + this._name + ": ");
			stringBuilder.Append("LINESTRING (");
			for (int i = 0; i < this._pts.Length; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(",");
				}
				stringBuilder.Append(this._pts[i].X + " " + this._pts[i].Y);
			}
			stringBuilder.Append(string.Concat(new object[]
			{
				")  ",
				base.Label,
				" ",
				this._depthDelta
			}));
			return stringBuilder.ToString();
		}

		public void Write(TextWriter outstream)
		{
			outstream.Write("edge " + this._name + ": ");
			outstream.Write("LINESTRING (");
			for (int i = 0; i < this.Points.Length; i++)
			{
				if (i > 0)
				{
					outstream.Write(",");
				}
				outstream.Write(this.Points[i].X + " " + this.Points[i].Y);
			}
			outstream.Write(string.Concat(new object[]
			{
				")  ",
				base.Label,
				" ",
				this._depthDelta
			}));
		}

		public void WriteReverse(TextWriter outstream)
		{
			outstream.Write("edge " + this._name + ": ");
			for (int i = this.Points.Length - 1; i >= 0; i--)
			{
				outstream.Write(this.Points[i] + " ");
			}
			outstream.WriteLine(string.Empty);
		}

		private Coordinate[] _pts;

		private Envelope _env;

		private readonly EdgeIntersectionList _eiList;

		private string _name;

		private MonotoneChainEdge _mce;

		private bool _isIsolated = true;

		private readonly Depth _depth = new Depth();

		private int _depthDelta;
	}
}
